package com.spring.aop1.service;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @Author: lxh
 * @name: LogAspect
 * Date: 2024/6/22  20:53
 */
@Order(0)
//数字越小越先执行
@Component // 切面也是组件
@Aspect // 切面类需要改注解进行标注
public class LogAspect {

    /**
     * @Before 注解标注的方法为前置通知
     * 注解中需要写切点表达式，因为 切面 = 通知 + 切点
     * 所以注解的属性value的属性值为切点表达式，告知要织入的切点
     * cw.study.spring.service包下的UserService类中的所有方法
     */
    // 通用切点表达式
    // 该通用切点表达式要跨类使用，在其他切面类中使用，前面写上包名类名即可
    // 如当前通用切点表达式在LogAspect类中，
    //
    // 该方法只是一个标记，方法名任意，方法体不用写代码
    @Pointcut("execution(* com.spring.aop1.service.UserService.*(..))")
    public void GeneralPointcutExpression() {}

    // 前置通知
    @Before("GeneralPointcutExpression()")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("优先级 0 前置通知...");
        // 获取目标方法的相关信息
        // 获取目标方法的签名，即 public void login() 方法的修饰符列表、方法名等
        // 方法的签名：访问权限修饰符开始到方法名
        Signature signature = joinPoint.getSignature();
        // 通过方法的签名可以获取方法的具体信息
        System.out.println("方法的方法名：" + signature.getName());
    }



    // 后置通知
    @AfterReturning("GeneralPointcutExpression()")
    public void afterReturningAdvice() {
        System.out.println("后置通知...");
    }
//    /**
//     * 环绕通知
//     *
//     * @param joinPoint 连接点
//     */
//    @Around("execution(* com.spring.aop01.UserService.*(..))")
//    public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
//        // 前环绕
//        System.out.println("前环绕...");
//        // 调用执行目标
//        joinPoint.proceed();
//        // 后环绕
//        System.out.println("后环绕...");
//    }
    // 最终通知
    @After("GeneralPointcutExpression()")
    public void afterAdvice() {
        System.out.println("最终通知...");
    }

    /**
     * 如果环绕通知中调将用目标方法时的异常在环绕通知代码中进行捕获，
     * 则后环绕通知会执行，相当于在环绕通知中将目标方法抛出的异常进行了捕获，
     * 异常被捕获程序可以继续向下执行
     * 结果：前环绕...
     * 前置通知...
     * 登录中...
     * 异常通知...
     * 最终通知...
     * 后环绕...
     * java.lang.RuntimeException: 运行时异常...
     */
    // 异常通知
    @AfterThrowing("GeneralPointcutExpression()")
    public void afterThrowingAdvice() {
        System.out.println("异常通知...");
    }

    /**
     * 环绕通知
     *
     * @param joinPoint 连接点
     */
    @Around("GeneralPointcutExpression()")
    public void aroundAdvice(ProceedingJoinPoint joinPoint) {
        // 前环绕
        System.out.println("前环绕...");
        // 调用执行目标
        try {
            joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        // 后环绕
        System.out.println("后环绕...");
    }





}
